<?php
/**
 * Redis连接池
 */
declare(strict_types=1);

namespace Libraries\Connections;

use Libraries\Config;
use Swoole\Database\RedisConfig;
use Swoole\Database\RedisPool;
use Redis;

class RedisConn
{
    private static $arrPool = []; // 连接池对象，常驻内存中

    /**
     * 取连接池
     * @param string $strName
     * @param bool $blnSetNx
     * @return RedisPool|null
     */
    private static function init(string $strName, bool $blnSetNx = false): ?RedisPool
    {
        if (isset(self::$arrPool[$strName])) {
            return self::$arrPool[$strName];
        }
        if (!$blnSetNx) {
            return null;
        }
        $objConfig = null;
        $intSize = 0;
        $arrConfig = Config::get('redis_' . $strName);
        $arrConfig || $arrConfig = Config::get('redis');
        if ($arrConfig) {
            $objConfig = (new RedisConfig())
                ->withHost($arrConfig['host'] ?? '127.0.0.1')
                ->withPort($arrConfig['port'] ?? 6379)
                ->withAuth($arrConfig['auth'] ?? '')
                ->withDbIndex($arrConfig['db_index'] ?? 0);
            $intSize = intval($arrConfig['pool_size'] ?? 5);
        }
        if ($objConfig && $intSize > 0) {
            self::$arrPool[$strName] = new RedisPool($objConfig, $intSize);
            return self::$arrPool[$strName];
        }
        return null;
    }

    /**
     * 关闭连接池，仅在WorkerStop中使用
     * @param string $strName
     * @return void
     */
    public static function close(string $strName = ''): void
    {
        if (strlen($strName)) {
            $objPool = self::init($strName);
            $objPool && $objPool->close();
            unset(self::$arrPool[$strName]);
        } else {
            foreach (self::$arrPool as $strName => $objPool) {
                $objPool && $objPool->close();
                unset(self::$arrPool[$strName]);
            }
        }
    }
    
    /**
     * 获取一个连接
     * @param string $strName
     * @return Redis|null
     */
    public static function get(string $strName = ''): ?Redis
    {
        strlen($strName) || $strName = 'default';
        $objPool = self::init($strName, true);
        if (!$objPool) {
            return null;
        }
        for ($i = 3; $i--;) {
            $objRedis = $objPool->get();
            if ($objRedis && $objRedis->isConnected()) {
                return $objRedis;
            }
            self::put(null, $strName);
        }
        return null;
    }

    /**
     * 归还一个连接，就算当前连接不可用，也要归还Null
     * @param Redis|null $objConn
     * @param string $strName
     * @return void
     */
    public static function put(?Redis $objConn, string $strName = ''): void
    {
        strlen($strName) || $strName = 'default';
        $objPool = self::init($strName);
        $objPool && $objPool->put($objConn);
    }
}
